// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module A_cse_ocs_dpa_aes10c_gf16_inv #(
	parameter POLY1 = 3
 )
 (
   input  logic [3:0] a,
   output logic [3:0] o );
   
   // internal signals
   wire         aA, aB;

   // continuous assignments (combinational logic)
   // Inverse computation in GF(16)

    generate
      if (POLY1 == 3)  begin
         assign aA = a[1] ^ a[2] ^ a[3] ^ ((a[1])&(a[2])&(a[3]));
         assign o[0] = aA ^ a[0] ^ (a[0] & a[2]) ^ (a[1] & a[2]) ^ ((a[1])&(a[2])&(a[0]));
         assign o[1] = (a[0] & a[1]) ^ (a[0] & a[2]) ^ (a[1] & a[2]) ^ a[3] ^ (a[1] & a[3]) ^ ((a[0])&(a[1])&(a[3]));
         assign o[2] = (a[0] & a[1]) ^ (a[0] & a[2]) ^  a[2] ^ a[3] ^ (a[0] & a[3]) ^ ((a[0])&(a[2])&(a[3]));
         assign o[3] = aA ^ (a[0] & a[3]) ^ (a[1] & a[3]) ^ (a[2] & a[3]);
      end
      if (POLY1 == 9)  begin
         assign aA = (a[3] & a[2] & a[0]) ^ (a[3] & a[0]);
         assign aB = (a[3] & a[2] & a[0]) ^ (a[3] & a[0]) ^ (a[3] & a[2] & a[1]);
         assign o[0] = aB ^ a[3] ^ a[0] ^ (a[3] & a[2]) ^ (a[1] & a[0]);
         assign o[1] = a[3] ^ a[2] ^ (a[3] & a[0]) ^ (a[2] & a[1]) ^ (a[3] & a[2] & a[1]) ^ (a[3] & a[2]) ^ (a[3] & a[1] & a[0]) ^ (a[2] & a[1] & a[0]);
         assign o[2] = aA ^ a[2] ^ a[1] ^ (a[3] & a[2]) ^ (a[3] & a[1]) ^ (a[2] & a[1]) ^ (a[1] & a[0]) ^ (a[2] & a[1] & a[0]);
         assign o[3] = aA ^ a[1] ^ (a[3] & a[1] & a[0]) ^ (a[2] & a[1]) ^ (a[2] & a[0]);
      end
      if (POLY1 == 15)  begin
         assign o[0] = a[1] ^ a[0] ^ (a[3] & a[2] & a[0]) ^ (a[3] & a[2]) ^ (a[3] & a[2] & a[1]) ^ (a[2] & a[0]);
         assign o[1] = a[1] ^ (a[2] & a[1] & a[0]) ^ (a[3] & a[1] & a[0]) ^ (a[3] & a[2] & a[1]) ^ (a[3] & a[0]) ^ (a[2] & a[0]) ^ (a[2] & a[1]);
         assign o[2] = a[3] ^ a[1] ^ (a[2] & a[1] & a[0]) ^ (a[3] & a[2] & a[0]) ^ (a[1] & a[0]) ^ (a[2] & a[0]);
         assign o[3] = a[2] ^ a[1] ^ (a[3] & a[1] & a[0]) ^ (a[3] & a[2] & a[0]) ^ (a[3] & a[1]) ^ (a[2] & a[0]);
      end
    endgenerate
   
endmodule

